{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### SVD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://mirrors.tencent.com/pypi/simple/, https://mirrors.tencent.com/repository/pypi/tencent_pypi/simple\n",
      "Requirement already satisfied: Pillow in /usr/local/lib/python3.8/dist-packages (9.2.0)\n",
      "Collecting tqdm\n",
      "  Downloading https://mirrors.tencent.com/pypi/packages/47/bb/849011636c4da2e44f1253cd927cfb20ada4374d8b3a4e425416e84900cc/tqdm-4.64.1-py2.py3-none-any.whl (78 kB)\n",
      "     |████████████████████████████████| 78 kB 883 kB/s             \n",
      "\u001b[?25hInstalling collected packages: tqdm\n",
      "Successfully installed tqdm-4.64.1\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\n",
      "\u001b[33mWARNING: You are using pip version 21.3.1; however, version 22.2.2 is available.\n",
      "You should consider upgrading via the '/usr/bin/python -m pip install --upgrade pip' command.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!pip install Pillow tqdm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1],\n",
       "       [1, 1],\n",
       "       [1, 0]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = np.array([[0,1],[1,1],[1,0]])\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3, 3) (2,) (2, 2)\n"
     ]
    }
   ],
   "source": [
    "u, s, vt = np.linalg.svd(A, full_matrices=True)\n",
    "print(u.shape, s.shape, vt.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-4.08248290e-01,  7.07106781e-01,  5.77350269e-01],\n",
       "       [-8.16496581e-01,  7.45552182e-17, -5.77350269e-01],\n",
       "       [-4.08248290e-01, -7.07106781e-01,  5.77350269e-01]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "u"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1.73205081, 1.        ])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.70710678, -0.70710678],\n",
       "       [-0.70710678,  0.70710678]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vt.T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.allclose(A, np.dot(u[:,:2]*s, vt))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.02120423e-16,  1.00000000e+00],\n",
       "       [ 1.00000000e+00,  1.00000000e+00],\n",
       "       [ 1.00000000e+00, -2.11898069e-16]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(u[:,:2]*s, vt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.73205081, 0.        ],\n",
       "       [0.        , 1.        ],\n",
       "       [0.        , 0.        ]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s_ = np.zeros((3,2))\n",
    "for i in range(2):\n",
    "    s_[i][i] = s[i]\n",
    "\n",
    "s_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.02120423e-16,  1.00000000e+00],\n",
       "       [ 1.00000000e+00,  1.00000000e+00],\n",
       "       [ 1.00000000e+00, -2.11898069e-16]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(np.dot(u, s_), vt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2022-10-10 20:07:02--  https://img.ixintu.com/download/jpg/202002/551b30f1527ef8570025beaccdb52607.jpg\n",
      "Resolving img.ixintu.com (img.ixintu.com)... 119.147.148.236\n",
      "Connecting to img.ixintu.com (img.ixintu.com)|119.147.148.236|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 451035 (440K) [image/jpeg]\n",
      "Saving to: ‘test.jpg’\n",
      "\n",
      "test.jpg            100%[===================>] 440.46K  --.-KB/s    in 0.03s   \n",
      "\n",
      "2022-10-10 20:07:02 (16.2 MB/s) - ‘test.jpg’ saved [451035/451035]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!rm -rf test.jpg && wget https://img.ixintu.com/download/jpg/202002/551b30f1527ef8570025beaccdb52607.jpg -O test.jpg\n",
    "!mkdir -p svd_pic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 50/50 [00:10<00:00,  4.85it/s]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import os\n",
    "from PIL import Image\n",
    "from tqdm import tqdm\n",
    "\n",
    "# 定义恢复函数，由分解后的矩阵恢复到原矩阵\n",
    "def restore(u, s, v, K): \n",
    "    '''\n",
    "    u:左奇异矩阵\n",
    "    v:右奇异矩阵\n",
    "    s:奇异值矩阵\n",
    "    K:奇异值个数\n",
    "    '''\n",
    "    m, n = len(u), len(v[0])\n",
    "    a = np.zeros((m, n))\n",
    "    for k in range(K):\n",
    "        uk = u[:, k].reshape(m, 1)\n",
    "        vk = v[k].reshape(1, n)\n",
    "        # 前k个奇异值的加总\n",
    "        a += s[k] * np.dot(uk, vk)   \n",
    "    a = a.clip(0, 255)\n",
    "    return np.rint(a).astype('uint8')\n",
    "\n",
    "A = np.array(Image.open(\"./test.jpg\", 'r'))\n",
    "# 对RGB图像进行奇异值分解\n",
    "u_r, s_r, v_r = np.linalg.svd(A[:, :, 0])    \n",
    "u_g, s_g, v_g = np.linalg.svd(A[:, :, 1])\n",
    "u_b, s_b, v_b = np.linalg.svd(A[:, :, 2])\n",
    "\n",
    "# 使用前50个奇异值\n",
    "K = 50 \n",
    "output_path = r'./svd_pic'\n",
    "# \n",
    "for k in tqdm(range(1, K+1)):\n",
    "    R = restore(u_r, s_r, v_r, k)\n",
    "    G = restore(u_g, s_g, v_g, k)\n",
    "    B = restore(u_b, s_b, v_b, k)\n",
    "    I = np.stack((R, G, B), axis=2)   \n",
    "    Image.fromarray(I).save('%s/svd_%d.jpg' % (output_path, k))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(959, 959, 3)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
